package com.cch.cooperation.api.support.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import com.cch.cooperation.api.common.properties.AppProperties;
import com.cch.cooperation.api.common.util.ImgUtil;
import com.cch.cooperation.dao.file.dto.FileDTO;
import com.cch.cooperation.api.support.dto.FileTmpDelDTO;
import com.cch.cooperation.api.support.util.SupportFileUtil;
import com.cch.cooperation.biz.common.lock.Locker;
import com.cch.cooperation.common.exception.BizException;
import com.cch.cooperation.common.util.SnowflakeIdUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.io.*;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class FileServiceImpl {

    @Resource
    private AppProperties appProperties;
    @Resource
    private RedissonClient client;
    @Resource
    private ContentCheckServiceImpl contentCheckService;

    private final static String FILE_TMP_KEY = "SUPPORT:FILE:TMP:";

    public FileDTO upload(String module, String fileName, InputStream inputStream, InputStream coverInputStream) {
        if (StrUtil.isEmpty(fileName)) {
            throw new BizException("文件名不能为空");
        }
        if (StrUtil.isEmpty(module)) {
            throw new BizException("模块名不能为空");
        }
        String suffix = FileUtil.getSuffix(fileName);
        String storeFileName = SnowflakeIdUtil.getIdStr() + "." + suffix;
        String relativePath = "/" + DateUtil.format(new Date(), "yyyyMMdd") + "/" + module + "/" + storeFileName;
        String path = appProperties.getFileUploadPath() + relativePath ;
        File file = FileUtil.writeFromStream(inputStream, path);
        // 图片内容审核
        if (SupportFileUtil.isImg(path)) {
            contentCheckService.checkImage(new ByteArrayInputStream(FileUtil.readBytes(file)));
        }
        log.info("[File] upload file path:{}", file.getAbsoluteFile());
        if (ObjectUtil.isNotNull(coverInputStream)) {
            String coverPath = appProperties.getFileUploadPath() + "/cover" + relativePath ;
            FileUtil.writeFromStream(coverInputStream, coverPath);
        }
        String id = MD5.create().digestHex16(path);
        return new FileDTO(
                id,
                fileName,
                appProperties.getFileDownloadBaseUrl() + relativePath,
                appProperties.getFileDownloadBaseUrl() + "/cover" + relativePath,
                SupportFileUtil.getParam(path)
        );
    }

    public InputStream file(String year, String module, String fileName) throws IOException {
        String relativePath = "/" + year + "/" + module + "/" + fileName;
        String path = appProperties.getFileUploadPath() + relativePath;
        if (SupportFileUtil.isImg(path)) {
            return magicImg(path);
        }
        return FileUtil.getInputStream(path);
    }

    public InputStream magicImg(String path) throws IOException {
        int idx = path.lastIndexOf('/');
        String fileName = path.substring(idx + 1);
        String[] imgArgs = fileName.split("!");
        // 创建魔图缩放
        if (imgArgs.length > 1 && !FileUtil.exist(path)) {
            String sizeParams = imgArgs[1].replaceAll("\\..+", "");
            String[] size = sizeParams.split("_");
            String oriPath = path.replace("!" + sizeParams, "");
            ImgUtil.compress(FileUtil.getInputStream(oriPath), FileUtil.getOutputStream(path), Integer.valueOf(size[0]), Integer.valueOf(size[1]));
        }
        // 返回正常尺寸
        return FileUtil.getInputStream(path);
    }

    @Locker(key = "'LOCK:FILE:TMP:EDIT:' + #bizId")
    public FileDTO uploadTmp(String bizId, String module, String fileName, InputStream inputStream, InputStream coverInputStream) {
        if (StrUtil.isEmpty(bizId)) {
            throw new BizException("业务id不能为空");
        }
        FileDTO file = upload(module, fileName, inputStream, coverInputStream);
        RBucket<List<FileDTO>> bucket = client.getBucket(FILE_TMP_KEY + bizId);
        List<FileDTO> tmpFiles = bucket.get();
        if (ObjectUtil.isNull(tmpFiles)) {
            tmpFiles = new ArrayList<>();
        }
        tmpFiles.add(file);
        bucket.set(tmpFiles, 1, TimeUnit.DAYS);
        return file;
    }

    public List<FileDTO> queryTmp(String bizId) {
        if (StrUtil.isEmpty(bizId)) {
            throw new BizException("业务id不能为空");
        }
        return client.<List<FileDTO>>getBucket(FILE_TMP_KEY + bizId).get();
    }

    @Locker(key = "'LOCK:FILE:TMP:EDIT:' + #req.bizId")
    public void deleteTmp(@Valid FileTmpDelDTO req) {
        RBucket<List<FileDTO>> bucket = client.getBucket(FILE_TMP_KEY + req.getBizId());
        List<FileDTO> tmpFiles = bucket.get();
        if (CollUtil.isEmpty(tmpFiles)) {
            return;
        }
        tmpFiles = tmpFiles.stream().filter(o -> !o.getId().equals(req.getId())).collect(Collectors.toList());
        bucket.set(tmpFiles, 1, TimeUnit.DAYS);
    }

}
